package mylab.starters.mybatis.interceptor.impl.datascope;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper;
import com.baomidou.mybatisplus.core.toolkit.PluginUtils;
import com.baomidou.mybatisplus.extension.parser.JsqlParserSupport;
import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
import lombok.*;
import lombok.extern.slf4j.Slf4j;
import mylab.starters.mybatis.interceptor.OrderlyInterceptor;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.Parenthesis;
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
import net.sf.jsqlparser.statement.select.*;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;

import java.sql.SQLException;
import java.util.List;


/**
 * MP自带的DataPermissionHandler只支持行过滤，不支持字段过滤
 */
@Slf4j
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
public class DataScopeInterceptor extends JsqlParserSupport implements InnerInterceptor,OrderlyInterceptor {
    private DataScopeHandler dataScopeHandler = new DefaultDataScopeHandler();

    @Override
    public int getOrder() {
        return OrderlyInterceptor.DataScope;
    }

    @Override
    public String getDescription() {
        return "数据权限插件";
    }

    @Override
    public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
        if (InterceptorIgnoreHelper.willIgnoreDataPermission(ms.getId())) return;
        String mappedStatementId = ms.getId();
        PluginUtils.MPBoundSql mpBs = PluginUtils.mpBoundSql(boundSql);
        mpBs.sql(parserSingle(mpBs.sql(), mappedStatementId));
    }

    @Override
    protected void processSelect(Select select, int index, String sql, Object obj) {
        SelectBody selectBody = select.getSelectBody();
        String mappedStatementId = (String) obj;
        if (selectBody instanceof PlainSelect) {
            processSelectBody(mappedStatementId, selectBody);
        } else if (selectBody instanceof SetOperationList) {
            SetOperationList setOperationList = (SetOperationList) selectBody;
            List<SelectBody> selectBodyList = setOperationList.getSelects();
            selectBodyList.forEach(s -> processSelectBody(mappedStatementId, s));
        }
    }

    protected void processSelectBody(String mappedStatementId, SelectBody selectBody) {
        if (!dataScopeHandler.needDataScope(mappedStatementId)) {
            //未要求做数据权限过滤
            return;
        }

        if (selectBody instanceof PlainSelect) {
            PlainSelect plainSelect = (PlainSelect) selectBody;
            this.setSelectItems(mappedStatementId, plainSelect);
            this.setWhere(mappedStatementId, plainSelect);
        } else {
            log.warn("数据权限未执行，不支持的selectBody:" + selectBody.toString());
        }
    }

    protected void setSelectItems(String mappedStatementId, PlainSelect plainSelect) {
        List<SelectItem> selectItems = dataScopeHandler.getSelectItems(mappedStatementId, plainSelect.getSelectItems());
        if (selectItems != null) {
            plainSelect.setSelectItems(selectItems);
        }
    }

    protected void setWhere(String mappedStatementId, PlainSelect plainSelect) {
        Expression sqlSegment = dataScopeHandler.getSqlSegment(mappedStatementId, plainSelect.getWhere());
        if (null != sqlSegment) {
            Expression expression = plainSelect.getWhere();
            expression = ObjectUtil.isNotEmpty(expression) ? new AndExpression(expression, new Parenthesis(sqlSegment)) : sqlSegment;
            plainSelect.setWhere(expression);
        }
    }

}
